#include "VideoChannel.h"

//原始包，不需要考虑关键帧
void dropAVFrame(queue<AVFrame *> &q) {
    if (!q.empty()) {
        AVFrame *frame = q.front();
        BaseChannel::releaseAVFrame(&frame);
        q.pop();
    }
}

//考虑关键帧
void dropAVPacket(queue<AVPacket *> &q) {
    while (!q.empty()) {
        AVPacket *packet = q.front();
//       判断是否是关键帧
        if (packet->flags != AV_PKT_FLAG_KEY) {
            BaseChannel::releaseAVPacket(&packet);
            q.pop();
        } else {
            break; // 如果是关键帧，不能丢，那就结束
        }
    }
}

VideoChannel::VideoChannel(int streamIndex, AVCodecContext *avCodecContext, AVRational time_base,
                           int fps)
        : BaseChannel(streamIndex, avCodecContext, time_base),
          fps(fps) {
    frames.setSyncCallback(dropAVFrame);
    packes.setSyncCallback(dropAVPacket);

}


void *task_video_decode(void *args) {
    auto *video_channel = static_cast<VideoChannel *>(args);
    video_channel->video_decode();
    return nullptr;//必须返回
}

void *task_video_play(void *args) {
    auto *video_channel = static_cast<VideoChannel *>(args);
    video_channel->video_play();
    return nullptr;//必须返回
}

void VideoChannel::start() {
    isPlay = 1;
    packes.setWork(1);
    frames.setWork(1);
//第一个线程，取出队列的压缩包进行编码，再将编码后的数据 push 到队列中
    pthread_create(&pid_video_decode, 0, task_video_decode, this);
//第二个线程 从队列中取出原始包，进行播放
    pthread_create(&pid_video_play, 0, task_video_play, this);
}

void VideoChannel::video_decode() {

    AVPacket *pck = nullptr;
    while (isPlay) {

        if (isPlay && frames.size() > 100) {
            av_usleep(10 * 1000);
            continue;
        }

        int ret = packes.getQueueAndDel(pck);
        if (!isPlay) break;
        if (!ret) {
            continue;   //没有成功  也要继续
        }
        ret = avcodec_send_packet(avCodecContext, pck);
        if (ret) {
            return;
        }

        AVFrame *frame = av_frame_alloc();
        ret = avcodec_receive_frame(avCodecContext, frame);
        if (ret == AVERROR(EAGAIN)) {
//          B帧参考前面成功，参考后面失败，可能P帧没出来，再拿一次就好了
            continue;
        } else if (ret != 0) {
            if (frame) {
                releaseAVFrame(&frame);
            }
            break;  //发生错误  直接停止
        }
        frames.insertToQueue(frame);
        av_packet_unref(pck);
        releaseAVPacket(&pck);

    }
    av_packet_unref(pck);
    releaseAVPacket(&pck);


}

void VideoChannel::video_play() {
    AVFrame *avFrame = 0;
    uint8_t *dst_data[4];
    int dstlinesize[4];
    av_image_alloc(dst_data,
                   dstlinesize,
                   avCodecContext->width,
                   avCodecContext->height,
                   AV_PIX_FMT_RGBA,
                   1);
    SwsContext *swsContext = sws_getContext(
//          输入参数
            avCodecContext->width,
            avCodecContext->height,
            avCodecContext->pix_fmt,  //自动获取MP4的像素格式

//          输出结果
            avCodecContext->width,
            avCodecContext->height,
            AV_PIX_FMT_RGBA,
            SWS_BILINEAR,
            NULL, NULL, NULL);
    while (isPlay) {
        int ret = frames.getQueueAndDel(avFrame);
        if (!isPlay) {
            break;
        }


        if (!ret) {
            continue;
        }
//      格式转换  YUV 转 RGBA
        sws_scale(
//              输入参数
                swsContext,
                avFrame->data,
                avFrame->linesize,
                0,
                avCodecContext->height,

//              输出结果
                dst_data, dstlinesize
        );

        // 公式：extra_delay = repeat_pict / (2*fps)
        double extra_delay = avFrame->repeat_pict / (2 * fps);
        double fps_delay = 1.0 / fps;
        double real_delay = extra_delay + fps_delay;
//        av_usleep(real_delay * 1000000);

        double video_time = avFrame->best_effort_timestamp * av_q2d(time_base);
        double audio_time = audioChannel->audio_time;

//      判断两个时间差值 快的等慢的，慢的追快的

        double time_diff = video_time - audio_time;
        if (time_diff > 0) {
//            控制视频播放器慢点
            if (time_diff > 1) {
//              差值很大，不会睡很久，
                av_usleep((real_delay * 2) * 1000000);
            } else {
                av_usleep((real_delay + time_diff) * 1000000);
            }
        } else if (time_diff < 0) {
//            追音频，控制视频播放快点  ，采用丢包策略
//            丢帧 I帧不能随意丢
//           fabs 对负数的操作，取绝对值
            if (fabs(time_diff) <= 0.05) {
                frames.sync();
                continue;
            }
        } else {
//           百分百同步
            LOGE("百分百同步了");
        }


        renderCallback(dst_data[0], avCodecContext->width, avCodecContext->height, dstlinesize[0]);
        releaseAVFrame(&avFrame); // 释放原始包，因为已经被渲染完了，没用了
        av_frame_unref(avFrame);
    }

    releaseAVFrame(&avFrame); // 释放原始包，因为已经被渲染完了，没用了
    av_frame_unref(avFrame);
    isPlay = 0;
    av_free(&dst_data[0]);
    sws_freeContext(swsContext);
}

void VideoChannel::setRenderCallback(RenderCallback renderCallback) {
    this->renderCallback = renderCallback;
}

void VideoChannel::setAudioChannel(AudioChannel *pChannel) {
    this->audioChannel = pChannel;
}


void VideoChannel::stop() {
    pthread_join(pid_video_decode, nullptr);
    pthread_join(pid_video_play, nullptr);

    isPlay = false;

    packes.setWork(0);
    frames.setWork(0);

    packes.clear();
    frames.clear();


}

VideoChannel::~VideoChannel() {
    DELETE(audioChannel)
}
